home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / vbcc-wos-src / vlink / linker.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  46KB  |  1,476 lines

  1. /* $VER: vlink linker.c V0.6a (19.12.98)
  2.  *
  3.  * This file is part of vlink, a portable linker for multiple
  4.  * object formats.
  5.  * Copyright (c) 1997-99  Frank Wille
  6.  *
  7.  * vlink is freeware and part of the portable and retargetable ANSI C
  8.  * compiler vbcc, copyright (c) 1995-99 by Volker Barthelmann.
  9.  * vlink may be freely redistributed as long as no modifications are
  10.  * made and nothing is charged for it. Non-commercial usage is allowed
  11.  * without any restrictions.
  12.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  13.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  14.  *
  15.  *
  16.  * v0.6a (19.12.98) phx
  17.  *       Endianess of linking process will be determined by the type
  18.  *       of the first object.
  19.  *       Support for little endian object file formats. All read/write
  20.  *       operation on the object data is done in current endianess.
  21.  * v0.6  (24.10.98) phx
  22.  *       Take base register section offset from FFFuncs.baseoff.
  23.  * v0.5e (05.10.98) phx
  24.  *       Linking a ID_LIBARCH object requires its PriPointers to be
  25.  *       added to the global list: add_priptrs().
  26.  *       Call make_priptr_objects() after processing all objects in
  27.  *       linker_resolve has finished. If there are entries in the Pri-
  28.  *       Pointers list, then create some artificial sections (usually
  29.  *       constructor and destructor lists).
  30.  *       insertnode() <-> insertbehind().
  31.  * v0.5d (22.08.98) phx
  32.  *       Faster memory allocation can be activated by #define FASTALLOC.
  33.  *       Directories are only scanned if needed (AmigaOS filesystem is
  34.  *       too slow).
  35.  * v0.5c (08.07.98) phx
  36.  *       ID_ARTIFICIAL objects, i.e. objects created by the linker
  37.  *       are supported.
  38.  * v0.5  (27.06.98) phx
  39.  *       Target-specific linker symbol support.
  40.  * v0.4  (05.06.98) phx
  41.  *       Rewrote linker_join(). Now it can be guaranteed, that first
  42.  *       all code sections will be linked, then the data and finally
  43.  *       the bss sections.
  44.  *       Rewrote find_lnksect(). A lot more factors are now involved
  45.  *       in the decision if two sections can be coalesced: relative
  46.  *       references between the two, both are addressed base-relative,
  47.  *       or target-specific factors.
  48.  *       New functions for detection of relative references:
  49.  *       addrelref(), copyrelrefs(), checkrelrefs().
  50.  *       assign_common() finds a bss section for common symbols.
  51.  * v0.3b (02.05.98) phx
  52.  *       There were still infinite loops, if an object comes without
  53.  *       any section.
  54.  * v0.3  (16.04.98) phx
  55.  *       Resolving ADDR16_HA/HI/LO references to a relocatable symbol
  56.  *       didn't work (2 bytes of the next instructions were overwritten).
  57.  *       Fixed print_function_name(). Didn't work, if symbols had
  58.  *       a known size. Additionally, it can differentiate between
  59.  *       'no type', 'function' and 'object' now.
  60.  *       Avoid infinite loops for object units without section in
  61.  *       linker_join().
  62.  * v0.2  (07.03.98) phx
  63.  *       Base relative relocations must not be resolved, if the output
  64.  *       file is a relocatable object again. Base relative xrefs were
  65.  *       even completely corrupted and overwrote the following
  66.  *       instruction.
  67.  *       Library units are linked immediately and are no longer always
  68.  *       the last units in an output file.
  69.  *       Base relative relocation didn't work for baseoff=0x8000.
  70.  * v0.1  (27.02.98) phx
  71.  *       First version that seems to link AmigaOS ADOS and EHF
  72.  *       objects and libraries. Many common features, like linking
  73.  *       sections together which have relative references, are
  74.  *       still missing. Also, PowerPC-ELF32 support is about to come.
  75.  * v0.0  (02.12.97) phx
  76.  *       File created.
  77.  */
  78.  
  79.  
  80. #define LINKER_C
  81. #include "vlink.h"
  82.  
  83.  
  84. static char namebuf[FNAMEBUFSIZE];
  85.  
  86. static const char *filetypes[] = {
  87.   "unknown",
  88.   "object",
  89.   "executable",NULL,
  90.   "shared object",NULL,NULL,NULL,
  91.   "library"
  92. };
  93.  
  94. static const char *sec_names[] = {
  95.   "undefined","code","data","bss",NULL
  96. };
  97.  
  98. void linker_init(struct GlobalVars *);
  99. void linker_load(struct GlobalVars *);
  100. void linker_relrefs(struct GlobalVars *);
  101. void linker_resolve(struct GlobalVars *);
  102. void linker_join(struct GlobalVars *);
  103. void linker_copy(struct GlobalVars *);
  104. void linker_write(struct GlobalVars *);
  105. void linker_cleanup(struct GlobalVars *);
  106. char *getobjname(struct ObjectUnit *);
  107. void print_function_name(struct Section *,unsigned long);
  108. bool trace_sym_access(struct GlobalVars *,char *);
  109.  
  110. static void resolve_reloc(struct GlobalVars *,struct LinkedSection *,
  111.                           struct Section *,struct Reloc *);
  112. static void resolve_xref(struct GlobalVars *,struct LinkedSection *,
  113.                          struct Section *,struct XReference *);
  114. static void newreloc(struct LinkedSection *,struct LinkedSection *,
  115.                      unsigned long,int32,uint8);
  116. static void assign_common(struct GlobalVars *);
  117. static char *maplibrary(struct GlobalVars *,struct InputFile *);
  118. static char *searchlib(struct GlobalVars *,char *,int);
  119. static char *scan_directory(char *,char *,int);
  120. static void addrelref(struct RelRef **,struct Section *);
  121. static void copyrelrefs(struct RelRef **,struct Section *);
  122. static bool checkrelrefs(struct RelRef *,struct Section *);
  123. static struct LinkedSection *create_lnksect(struct GlobalVars *,char *,
  124.                                             uint8,uint8,uint8,uint8);
  125. static struct LinkedSection *find_lnksect(struct GlobalVars *,
  126.                                           struct Section *);
  127. static void combine_sections(struct LinkedSection *,struct Section *,uint8);
  128. static void print_symbol(FILE *,struct Symbol *);
  129. static char *protstring(uint8);
  130.  
  131.  
  132.  
  133. void linker_init(struct GlobalVars *gv)
  134. {
  135.   initlist(&gv->linkfiles);
  136.   initlist(&gv->selobjects);
  137.   initlist(&gv->libobjects);
  138.   initlist(&gv->sharedobjects);
  139.   gv->symbols = alloc_hashtable(SYMHTABSIZE);
  140.   initlist(&gv->pripointers);
  141.   gv->big_endian = -1;
  142. }
  143.  
  144.  
  145. void linker_load(struct GlobalVars *gv)
  146. /* load all objects and libraries into memory, identify their */
  147. /* format, then read all symbols and convert into internal format */
  148. {
  149.   struct InputFile *ifn = (struct InputFile *)gv->inputlist.first;
  150.   struct InputFile *nextifn;
  151.   struct LinkFile *lf;
  152.   uint8 *objptr;
  153.   char *objname;
  154.   unsigned long objlen;
  155.   int i,ff;
  156.  
  157.   if (gv->trace_file)
  158.     fprintf(gv->trace_file,"\nLoading files:\n\n");
  159.  
  160.   while (nextifn = (struct InputFile *)ifn->n.next) {
  161.     if (ifn->lib) {
  162.       if (!(objptr = (uint8 *)maplibrary(gv,ifn))) {
  163.         sprintf(namebuf,"-l%s",ifn->name);
  164.         error(8,namebuf);  /* cannot open -lxxx */
  165.       }
  166.     }
  167.     else {
  168.       if (objptr = (uint8 *)mapfile(ifn->name))
  169.         strcpy(namebuf,ifn->name);
  170.       else
  171.         error(8,ifn->name);  /* cannot open xxx */
  172.     }
  173.     objlen = *(size_t *)(objptr - sizeof(size_t));
  174.     objname = base_name(namebuf);
  175.  
  176.     /* determine the object's file format */
  177.     for (i=0,ff=ID_UNKNOWN; fff[i]; i++) {
  178.       if ((ff = (fff[i]->identify)(objname,objptr,objlen)) != ID_UNKNOWN)
  179.         break;
  180.     }
  181.     if (ff == ID_UNKNOWN)
  182.       error(11,objname);  /* File format not recognized */
  183.  
  184.     /* use endianess of first object read */
  185.     if (gv->big_endian < 0)
  186.       gv->big_endian = fff[i]->big_endian;
  187.     else if (gv->big_endian != fff[i]->big_endian)
  188.       error(61,objname);  /* endianess differs from previous objects */
  189.  
  190.     /* create new link file node */
  191.     lf = (struct LinkFile *)alloc(sizeof(struct LinkFile));
  192.     lf->pathname = allocstring(namebuf);
  193.     lf->filename = base_name(lf->pathname);
  194.     lf->data = objptr;
  195.     lf->length = objlen;
  196.     lf->format = (uint8)i;
  197.     lf->type = (uint8)ff;
  198.     if (gv->trace_file)
  199.       fprintf(gv->trace_file,"%s (%s %s)\n",namebuf,fff[i]->tname,
  200.                                             filetypes[ff]);
  201.  
  202.     /* read the file and convert into internal format */
  203.     fff[i]->readconv(gv,lf);
  204.     addtail(&gv->linkfiles,&lf->n);  /* not really needed */
  205.  
  206.     ifn = nextifn;  /* next input file */
  207.   }
  208. }
  209.  
  210.  
  211. void linker_resolve(struct GlobalVars *gv)
  212. /* Resolve all symbol references and pull the required objects into */
  213. /* the gv->selobjects list. */
  214. {
  215.   bool priptrs_made = FALSE;
  216.   struct ObjectUnit *obj = (struct ObjectUnit *)gv->selobjects.first;
  217.   static const char *pulltxt = " needed due to ";
  218.  
  219.   if (gv->trace_file)
  220.     fprintf(gv->trace_file,"\nDigesting symbol information:\n\n");
  221.  
  222.   if (obj->n.next == NULL)
  223.     return;  /* no objects in list */
  224.  
  225.   do {
  226.     struct Section *sec = (struct Section *)obj->sections.first;
  227.     struct Section *nextsec;
  228.     struct XReference *xref,*nextxref;
  229.     struct Symbol *xdef;
  230.     struct ObjectUnit *pull_unit;
  231.  
  232.     /* all sections of this object are checked for external references */
  233.     while (nextsec = (struct Section *)sec->n.next) {
  234.       xref = (struct XReference *)sec->xrefs.first;
  235.       while (nextxref = (struct XReference *)xref->n.next) {
  236.  
  237.         if (!(xdef = findsymbol(gv,xref->name))) {
  238.           if (!(xdef = fff[gv->dest_format]->lnksymbol(gv,sec,xref))) {
  239.             /* undefined reference */
  240.             if (!gv->dest_object) {
  241.               print_function_name(sec,xref->offset);
  242.               error(21,getobjname(sec->obj),sec->name,xref->offset,
  243.                     xref->name);
  244.             }
  245.             xref = nextxref;
  246.             continue;
  247.           }
  248.         }
  249.  
  250.         /* reference resolved */
  251.         if (xdef->relsect) {
  252.           pull_unit = xdef->relsect->obj;
  253.  
  254.           switch (pull_unit->lnkfile->type) {
  255.             case ID_ARTIFICIAL:
  256.               /* linker-generated object - insert it behind the curr. obj. */
  257.               if (gv->map_file) {
  258.                 fprintf(gv->map_file,
  259.                         "artificial object (%s) created due to %s\n",
  260.                         pull_unit->objname,xref->name);
  261.                 /* "artificial object (name.o) created due to @__name" */
  262.               }
  263.               insertbehind(&obj->n,&pull_unit->n);
  264.               pull_unit->flags |= OUF_LINKED;
  265.               /* turn into a normal object */
  266.               pull_unit->lnkfile->type = ID_OBJECT;
  267.               xref->symbol = xdef;  /* unknown reference was resolved */
  268.               break;
  269.  
  270.             case ID_SHAREDOBJ:
  271.               if (!(pull_unit->flags & OUF_LINKED)) {
  272.                 if (gv->map_file) {
  273.                   fprintf(gv->map_file,"%s%s%s\n",
  274.                           pull_unit->lnkfile->pathname,pulltxt,xref->name);
  275.                   /* Example: "/usr/lib/libc.so.12.0 needed due to _atexit" */
  276.                 }
  277.                 insertbehind(&obj->n,remnode(&pull_unit->n));
  278.                 add_priptrs(gv,pull_unit);
  279.                 pull_unit->flags |= OUF_LINKED;
  280.               }
  281.               break;
  282.  
  283.             case ID_LIBARCH:
  284.               if (!(pull_unit->flags & OUF_LINKED)) {
  285.                 if (gv->map_file) {
  286.                   fprintf(gv->map_file,"%s (%s)%s%s\n",
  287.                           pull_unit->lnkfile->pathname,pull_unit->objname,
  288.                           pulltxt,xref->name);
  289.                   /* "/usr/lib/libc.a (atexit.o) needed due to _atexit" */
  290.                 }
  291.                 insertbehind(&obj->n,remnode(&pull_unit->n));
  292.                 add_priptrs(gv,pull_unit);
  293.                 pull_unit->flags |= OUF_LINKED;
  294.               }
  295.               /* fall through */
  296.  
  297.             default:
  298.               xref->symbol = xdef;  /* unknown reference was resolved */
  299.               break;
  300.           }
  301.         }
  302.         else
  303.           xref->symbol = xdef;
  304.  
  305.         xref = nextxref;
  306.       }
  307.  
  308.       sec = nextsec;  /* resolve ext. references of next section */
  309.     }
  310.  
  311.     if (obj->n.next->next == NULL && !priptrs_made) {
  312.       make_priptr_objects(gv);  /* PriPointer objects always at last */
  313.       priptrs_made = TRUE;
  314.     }
  315.     obj = (struct ObjectUnit *)obj->n.next;
  316.   }
  317.   while (obj->n.next);
  318. }
  319.  
  320.  
  321. void linker_relrefs(struct GlobalVars *gv)
  322. /* All relocations and unresolved xrefs with a relative reference */
  323. /* to other sections are collected. A second task is to detect */
  324. /* base-relative references and set the approriate flag of the */
  325. /* referenced section. */
  326. {
  327.   struct ObjectUnit *obj = (struct ObjectUnit *)gv->selobjects.first;
  328.   struct ObjectUnit *nextobj;
  329.  
  330.   /*@@@ find a better place for this: */
  331.   assign_common(gv);  /* find a bss section for common symbols */
  332.  
  333.   while (nextobj = (struct ObjectUnit *)obj->n.next) {
  334.     struct Section *sec = (struct Section *)obj->sections.first;
  335.     struct Section *nextsec;
  336.  
  337.     while (nextsec = (struct Section *)sec->n.next) {
  338.       struct Symbol *xdef;
  339.       struct XReference *xref = (struct XReference *)sec->xrefs.first;
  340.       struct XReference *nextxref;
  341.       struct Reloc *reloc = (struct Reloc *)sec->relocs.first;
  342.       struct Reloc *nextreloc;
  343.       struct RelRef **rr = &sec->relrefs;
  344.  
  345.       *rr = NULL;
  346.       while (nextxref = (struct XReference *)xref->n.next) {
  347.         if (xdef = xref->symbol) {
  348.           if (xdef->relsect!=NULL && xdef->relsect!=sec &&
  349.               (xdef->type==SYM_RELOC || xdef->type==SYM_COMMON)) {
  350.  
  351.             if ((xref->type & R_MASK) == R_REL)
  352.               /* relative reference to different section */
  353.               addrelref(rr,xdef->relsect);
  354.  
  355.             else if ((xref->type & R_MASK) == R_BASEREL)
  356.               /* other section is accessed base relative from this one */
  357.               xdef->relsect->flags |= SF_SMALLDATA;
  358.           }
  359.         }
  360.         xref = nextxref;
  361.       }
  362.  
  363.       while (nextreloc = (struct Reloc *)reloc->n.next) {
  364.         if (reloc->relocsect.ptr != sec) {
  365.  
  366.           if ((reloc->type & R_MASK) == R_REL)
  367.             /* relative reference to different section */
  368.             addrelref(rr,reloc->relocsect.ptr);
  369.  
  370.           else if ((reloc->type & R_MASK) == R_BASEREL)
  371.             /* other section is accessed base relative from this one */
  372.             reloc->relocsect.ptr->flags |= SF_SMALLDATA;
  373.         } 
  374.        reloc = nextreloc;
  375.       }
  376.  
  377.       sec = nextsec;
  378.     }
  379.     obj = nextobj;
  380.   }
  381. }
  382.  
  383.  
  384. void linker_join(struct GlobalVars *gv)
  385. /* Join the sections with same name and type. Calculate their */
  386. /* virtual address and size. */
  387. {
  388.   struct ObjectUnit *obj,*nextobj;
  389.   uint8 stype;
  390.  
  391.   if (gv->trace_file)
  392.     fprintf(gv->trace_file,"Joining selected sections:\n\n");
  393.  
  394.   for (stype=0; stype<=ST_LAST; stype++) {
  395.     /* join sections, beginning with ST_CODE, then ST_DATA and ST_UDATA */
  396.     obj = (struct ObjectUnit *)gv->selobjects.first;
  397.  
  398.     while (nextobj = (struct ObjectUnit *)obj->n.next) {
  399.       struct Section *sec = (struct Section *)obj->sections.first;
  400.       struct Section *nextsec;
  401.  
  402.       if (obj->lnkfile->type != ID_SHAREDOBJ) {
  403.         while (nextsec = (struct Section *)sec->n.next) {
  404.           struct LinkedSection *ls;
  405.  
  406.           if (sec->type == stype) {
  407.             unsigned long abytes;
  408.  
  409.             if (!(ls = find_lnksect(gv,sec))) {
  410.               ls = create_lnksect(gv,sec->name,sec->type,sec->flags,
  411.                                   sec->protection,sec->alignment);
  412.             }
  413.             abytes = align(ls->base+ls->size,sec->alignment);
  414.             sec->lnksec = ls;
  415.             sec->offset = ls->size + abytes;
  416.             sec->va = ls->base + sec->offset;
  417.             ls->size += sec->size + abytes;
  418.             if (!(sec->flags & SF_UNINITIALIZED))
  419.               ls->filesize += sec->size + abytes;
  420.             /* move into LinkedSection */
  421.             copyrelrefs(&ls->relrefs,sec);
  422.             addtail(&ls->sections,remnode(&sec->n));
  423.           }
  424.           sec = nextsec;
  425.         }
  426.       }
  427.       obj = nextobj;
  428.     }
  429.   }
  430.  
  431.   if (gv->map_file) {
  432.     /* print file names and the new addresses of their sections */
  433.  
  434.     fprintf(gv->map_file,"\nFiles:\n\n");
  435.     obj = (struct ObjectUnit *)gv->selobjects.first;
  436.  
  437.     while (nextobj = (struct ObjectUnit *)obj->n.next) {
  438.       struct LinkFile *lfile = obj->lnkfile;
  439.       struct LinkedSection *ls = (struct LinkedSection *)gv->lnksec.first;
  440.       struct LinkedSection *nextls;
  441.       char sep = ' ';
  442.  
  443.       if (lfile->type == ID_LIBARCH)
  444.         fprintf(gv->map_file,"  %s (%s)",lfile->pathname,obj->objname);
  445.       else
  446.         fprintf(gv->map_file,"  %s",obj->objname);
  447.  
  448.       if (lfile->type != ID_SHAREDOBJ) {
  449.         while (nextls = (struct LinkedSection *)ls->n.next) {
  450.           struct Section *sec = (struct Section *)ls->sections.first;
  451.           struct Section *nextsec;
  452.  
  453.           while (nextsec = (struct Section *)sec->n.next) {
  454.             if (sec->obj == obj) {  /* section came from this object? */
  455.               fprintf(gv->map_file,"%c %s %lx(%lx)",sep,ls->name,
  456.                       sec->va,sec->size);
  457.               sep = ',';
  458.             }
  459.             sec = nextsec;
  460.           }
  461.           ls = nextls;
  462.         }
  463.       }
  464.  
  465.       if (sep == ',')  /* any sections listed? */
  466.         fprintf(gv->map_file," hex\n");
  467.       else
  468.         fprintf(gv->map_file,"  symbols only\n"); /* empty or shared obj. */
  469.  
  470.       obj = nextobj;
  471.     }
  472.   }
  473. }
  474.  
  475.  
  476. void linker_copy(struct GlobalVars *gv)
  477. /* Merge contents of linked sections, fix symbol offsets and */
  478. /* allocate common symbol data. */
  479. {
  480.   struct LinkedSection *ls = (struct LinkedSection *)gv->lnksec.first;
  481.   struct LinkedSection *nextls;
  482.   struct Section *sec,*nextsec;
  483.  
  484.   if (gv->trace_file)
  485.     fprintf(gv->trace_file,"\n");
  486.   if (gv->map_file)
  487.     fprintf(gv->map_file,"\n");
  488.   while (nextls = (struct LinkedSection *)ls->n.next) {
  489.     struct Section *sec = (struct Section *)ls->sections.first;
  490.     struct Section *nextsec;
  491.  
  492.     if (gv->trace_file)
  493.       fprintf(gv->trace_file,"Copying %s:\n\n",ls->name);
  494.     if (gv->map_file)
  495.       fprintf(gv->map_file,"\nSymbols of %s:\n\n",ls->name);
  496.     if (!(ls->flags&SF_UNINITIALIZED))
  497.       ls->data = alloczero(ls->size);
  498.  
  499.     while (nextsec = (struct Section *)sec->n.next) {
  500.       struct Symbol *sym;
  501.       int i;
  502.       unsigned long n;
  503.  
  504.       if (ls->data && sec->data) {
  505.         /* copy section contents */
  506.         memcpy(ls->data+sec->offset,sec->data,sec->size);
  507.       }
  508.  
  509.       /* find section symbols and fix their offsets */
  510.       for (i=0; i<OBJSYMHTABSIZE; i++) {
  511.         sym = sec->obj->objsyms[i];
  512.         while (sym) {
  513.           if (sym->relsect == sec) {  /* symbol defined in this section */
  514.             switch (sym->type) {
  515.               case SYM_RELOC:
  516.                 sym->value += sec->offset;  /* fix offset for reloc symbols */
  517.                 break;
  518.               case SYM_COMMON:
  519.                 if (sec->obj->lnkfile->type != ID_SHAREDOBJ) {
  520.                   /* allocate common symbol and transform into SYM_RELOC */
  521.                   if (!(sec->type&SF_UNINITIALIZED))
  522.                     ierror("linker_relocate(): Common %s was defined in "
  523.                            "%s of %s, which is not a bss-type section",
  524.                            sym->name,sec->name,sec->obj->objname);
  525.                   n = align(ls->base+ls->size,sym->value);
  526.                   sym->value = ls->size + n;
  527.                   sym->type = SYM_RELOC;
  528.                   ls->size += n + sym->size;
  529.                   if (gv->map_file)
  530.                     fprintf(gv->map_file,
  531.                             "Allocating common %s: %x at %x\n",
  532.                             sym->name,(int)sym->size,
  533.                             (int)(ls->base+sym->value));
  534.                 }
  535.                 break;
  536.             }
  537.             addtail(&ls->symbols,&sym->n);
  538.             if (gv->map_file)
  539.               print_symbol(gv->map_file,sym);
  540.           }
  541.           sym = sym->obj_chain;
  542.         }
  543.       }
  544.       sec = nextsec;
  545.     }
  546.     ls = nextls;
  547.   }
  548. }
  549.  
  550.  
  551. void linker_relocate(struct GlobalVars *gv)
  552. /* Fix relocations, resolve x-references and create more relocations, */
  553. /* if required. */
  554. {
  555.   struct LinkedSection *ls = (struct LinkedSection *)gv->lnksec.first;
  556.   struct LinkedSection *nextls;
  557.   struct Section *sec,*nextsec;
  558.  
  559.   while (nextls = (struct LinkedSection *)ls->n.next) {
  560.     struct Section *sec = (struct Section *)ls->sections.first;
  561.     struct Section *nextsec;
  562.  
  563.     if (!(ls->flags&SF_UNINITIALIZED)) {
  564.       if (gv->trace_file)
  565.         fprintf(gv->trace_file,"Relocating %s:\n\n",ls->name);
  566.  
  567.       while (nextsec = (struct Section *)sec->n.next) {
  568.         struct Reloc *rel;
  569.         struct XReference *xref;
  570.  
  571.         /* copy and fix relocations */
  572.         while (rel = (struct Reloc *)remhead(&sec->relocs)) {
  573.           rel->offset += sec->offset;
  574.           rel->addend += rel->relocsect.ptr->offset;
  575.           rel->relocsect.lnk = rel->relocsect.ptr->lnksec;
  576.           if ((rel->type&R_MASK) != R_ADDR) {
  577.             /* relative relocations can be resolved */
  578.             resolve_reloc(gv,ls,sec,rel);
  579.           }
  580.           else {
  581.             /* absolute relocations remain */
  582.             writesection(gv,ls->data+rel->offset,rel->type,
  583.                          (uint32)rel->addend);  /* write new addend */
  584.             addtail(&ls->relocs,&rel->n);
  585.           }
  586.         }
  587.  
  588.         /* resolve, fix and copy x-references */
  589.         while (xref = (struct XReference *)remhead(&sec->xrefs)) {
  590.           xref->offset += sec->offset;
  591.           if (xref->symbol)
  592.             /* resolve xref - turn into relocation, if required */
  593.             resolve_xref(gv,ls,sec,xref);
  594.           else
  595.             /* xref remains in output file */
  596.             addtail(&ls->xrefs,&xref->n);
  597.         }
  598.         sec = nextsec;
  599.       }      
  600.     }
  601.     ls = nextls;
  602.   }
  603. }
  604.  
  605.  
  606. void linker_write(struct GlobalVars *gv)
  607. {
  608.   FILE *f;
  609.  
  610.   if (!gv->errflag) {  /* no error? */
  611.     if (gv->trace_file)
  612.       fprintf(gv->trace_file,"\nCreating output file %s (%s).\n",
  613.               gv->dest_name,fff[gv->dest_format]->tname);
  614.  
  615.     /* write output file */
  616.     if (f = fopen(gv->dest_name,"w")) {
  617.       if (gv->dest_sharedobj)
  618.         fff[gv->dest_format]->writeshared(gv,f);
  619.       else if (gv->dest_object)
  620.         fff[gv->dest_format]->writeobject(gv,f);
  621.       else
  622.         fff[gv->dest_format]->writeexec(gv,f);
  623.       fclose(f);
  624.     }
  625.     else  /* Can't create output file */
  626.       error(29,gv->dest_name);
  627.   }
  628. }
  629.  
  630.  
  631. void linker_cleanup(struct GlobalVars *gv)
  632. {
  633. }
  634.  
  635.  
  636. static void resolve_reloc(struct GlobalVars *gv,struct LinkedSection *ls,
  637.                           struct Section *sec,struct Reloc *r)
  638. /* Resolve relative and base-relative relocations. */
  639. {
  640.   char be = gv->big_endian;
  641.   uint8 *p = ls->data + r->offset;
  642.   int biterr = 0;
  643.  
  644.   if ((r->type&R_MASK) == R_REL) {
  645.     /*********************************/
  646.     /* Normal, PC-relative reference */
  647.     /*********************************/
  648.  
  649.     if (r->relocsect.lnk == ls) {
  650.       /* Relative reloc offset must be from the same section */
  651.       int32 d = r->addend - r->offset;
  652.   
  653.       switch (r->type) {
  654.         case R_REL32:
  655.           write32(be,p,(uint32)d);
  656.           break;
  657.   
  658.         case R_REL26:
  659.           biterr = checkrange(d,3,TRUE);
  660.           write32(be,p,(read32(be,p) & 0xfc000003)
  661.                        | (((uint32)d)&0x3fffffc));
  662.           break;
  663.   
  664.         case R_REL16:
  665.           biterr = checkrange(d,2,TRUE);
  666.           write16(be,p,(uint16)d);
  667.           break;
  668.  
  669.         /* @@@ currently no differentiation between the following */
  670.         case R_REL14:
  671.         case R_REL14_BRTAKEN:
  672.         case R_REL14_BRNTAKEN:
  673.           biterr = checkrange(d,2,TRUE);
  674.           write16(be,p,(read16(be,p) & 3) | (((uint16)d)&0xfffc));
  675.           break;
  676.   
  677.         case R_REL8:
  678.           biterr = checkrange(d,1,TRUE);
  679.           *p = (uint8)d;
  680.           break;
  681.   
  682.         default:  /* relative relocation type not supported */
  683.           ierror("resolve_reloc(): Unsupported relative relocation "
  684.                  "type %d",(int)r->type);
  685.           break;
  686.       }
  687.     }  
  688.     else {  /* error: Illegal relative reference on a different section */
  689.       print_function_name(sec,r->offset);
  690.       error(24,getobjname(sec->obj),sec->name,r->offset-sec->offset,
  691.             r->relocsect.lnk->name,r->addend);
  692.     }
  693.   }
  694.  
  695.   /***************************/
  696.   /* Base relative reference */
  697.   /***************************/
  698.   else {
  699.     if (!gv->dest_object) {
  700.       /* resolve base-relative relocation for executable file */
  701.       int32 d = r->addend - fff[gv->dest_format]->baseoff;
  702.  
  703.       switch (r->type) {
  704.         case R_BASEREL32:
  705.           write32(be,p,(uint32)d);
  706.           break;
  707.  
  708.         case R_BASEREL26:
  709.           biterr = checkrange(d,3,TRUE);
  710.           write32(be,p,(read32(be,p) & 0xfc000003)
  711.                        | (((uint32)d)&0x3fffffc));
  712.           break;
  713.  
  714.         case R_BASEREL16:
  715.           biterr = checkrange(d,2,TRUE);
  716.           write16(be,p,(uint16)d);
  717.           break;
  718.   
  719.         case R_BASEREL8:
  720.           biterr = checkrange(d,1,TRUE);
  721.           *p = (uint8)d;
  722.           break;
  723.  
  724.         default:  /* base-relative relocation type not supported */
  725.           ierror("resolve_reloc(): Unsupported base relative relocation "
  726.                  "type %d",(int)r->type);
  727.           break;
  728.       }
  729.     }
  730.  
  731.     else {  
  732.       /* destination is a relocatable object file, */
  733.       /* so create a new base-relative relocation entry */
  734.       int32 d = r->addend;
  735.  
  736.       switch (r->type) {
  737.         case R_BASEREL32:
  738.           write32(be,p,(uint32)d);
  739.           break;
  740.  
  741.         case R_BASEREL26:
  742.           biterr = checkrange(d,3,TRUE);
  743.           write32(be,p,(read32(be,p) & 0xfc000003)
  744.                        | (((uint32)d) & 0x3fffffc));
  745.           break;
  746.  
  747.         case R_BASEREL16:
  748.           biterr = checkrange(d,2,TRUE);
  749.           write16(be,p,(uint16)d);
  750.           break;
  751.   
  752.         case R_BASEREL8:
  753.           biterr = checkrange(d,1,TRUE);
  754.           *p = (uint8)d;
  755.           break;
  756.  
  757.         default:  /* base-relative relocation type not supported */
  758.           ierror("resolve_reloc(): Unsupported base relative relocation "
  759.                  "type %d",(int)r->type);
  760.           break;
  761.       }
  762.       newreloc(ls,r->relocsect.lnk,r->offset,r->addend,r->type);
  763.     }
  764.  
  765.     if (biterr) {  /* relative reference out of range! */
  766.       print_function_name(sec,r->offset);
  767.       error(25,getobjname(sec->obj),sec->name,r->offset-sec->offset,
  768.             biterr,r->relocsect.lnk->name,r->addend);
  769.     }
  770.   }
  771. }
  772.  
  773.  
  774. static void resolve_xref(struct GlobalVars *gv,struct LinkedSection *ls,
  775.                          struct Section *sec,struct XReference *xref)
  776. /* The external reference xref can be resolved by the symbol definition */
  777. /* xdef = xref->symbol. The assignment of a relocatable symbol requires */
  778. /* the creation of a new Reloc entry for the section. */
  779. {
  780.   static char *ierr_func = "resolve_xref(): ";
  781.   static char *ierr_rtype = "Unsupported xref relocation type ";
  782.   struct Symbol *xdef = xref->symbol;
  783.   char be = gv->big_endian;
  784.   uint8 *p = ls->data + xref->offset;
  785.   int32 x;
  786.   int biterr = 0;
  787.  
  788.   /* last chance to initialize a target-specific linker symbol */
  789.   if (xdef->flags & SYMF_LNKSYM)
  790.     fff[gv->dest_format]->setlnksym(gv,xdef,xref);
  791.  
  792.   /**************************************************/
  793.   /* Relative/absolute reference to absolute symbol */
  794.   /**************************************************/
  795.   if (xdef->type == SYM_ABS) {
  796.     /* resolve x-reference to an absolute symbol */
  797.     x = (int32)xdef->value + xref->addend;
  798.  
  799.     switch (xref->type) {
  800.       case R_ADDR32:
  801.       case R_REL32:
  802.       case R_BASEREL32:
  803.         write32(be,p,(uint32)x);
  804.         break;
  805.  
  806.       case R_ADDR26:
  807.         biterr = checkrange(x,3,FALSE);
  808.         write32(be,p,(read32(be,p) & 0xfc000003)
  809.                      | (((uint32)x)&0x3fffffc));
  810.         break;
  811.  
  812.       case R_REL26:
  813.       case R_BASEREL26:
  814.         biterr = checkrange(x,3,TRUE);
  815.         write32(be,p,(read32(be,p) & 0xfc000003)
  816.                      | (((uint32)x)&0x3fffffc));
  817.         break;
  818.  
  819.       case R_ADDR16:
  820.         biterr = checkrange(x,2,FALSE);
  821.         write16(be,p,(uint16)x);
  822.         break;
  823.  
  824.       /* @@@ currently no differentiation between the following */
  825.       case R_ADDR14:
  826.       case R_ADDR14_BRTAKEN:
  827.       case R_ADDR14_BRNTAKEN:
  828.         biterr = checkrange(x,2,FALSE);
  829.         write16(be,p,(read16(be,p) & 3) | (((uint16)x)&0xfffc));
  830.         break;
  831.  
  832.       case R_REL16:
  833.       case R_BASEREL16:
  834.         biterr = checkrange(x,2,TRUE);
  835.         write16(be,p,(uint16)x);
  836.         break;
  837.  
  838.       /* @@@ currently no differentiation between the following */
  839.       case R_REL14:
  840.       case R_REL14_BRTAKEN:
  841.       case R_REL14_BRNTAKEN:
  842.         biterr = checkrange(x,2,TRUE);
  843.         write16(be,p,(read16(be,p) & 3) | (((uint32)x)&0xfffc));
  844.         break;
  845.  
  846.       case R_ADDR16_LO:
  847.         write16(be,p,(uint16)((uint32)x&0xffff));
  848.         break;
  849.  
  850.       case R_ADDR16_HI:
  851.         write16(be,p,(uint16)(((uint32)x>>16)&0xffff));
  852.         break;
  853.  
  854.       case R_ADDR16_HA:
  855.         write16(be,p,(uint16)((((uint32)x+0x8000)>>16)&0xffff));
  856.         break;
  857.  
  858.       case R_ADDR8:
  859.         biterr = checkrange(x,1,FALSE);
  860.         *p = (uint8)x;
  861.         break;
  862.  
  863.       case R_REL8:
  864.       case R_BASEREL8:
  865.         biterr = checkrange(x,1,TRUE);
  866.         *p = (uint8)x;
  867.         break;
  868.  
  869.       default:  /* xref relocation type not supported */
  870.         ierror("%s%s%d",ierr_func,ierr_rtype,(int)xref->type);
  871.         break;
  872.     }
  873.     if (biterr) {  /* referenced absolute symbol out of range! */
  874.       print_function_name(sec,xref->offset);
  875.       error(26,getobjname(sec->obj),sec->name,xref->offset-sec->offset,
  876.             xdef->name,xdef->value,(uint32)xref->addend,biterr);
  877.     }
  878.   }
  879.  
  880.   else if (xdef->type == SYM_RELOC) {
  881.     /* resolve x-reference to a relocatable symbol */
  882.  
  883.     /********************************************/
  884.     /* Relative reference to relocatable symbol */
  885.     /********************************************/
  886.     if ((xref->type & R_MASK) == R_REL) {
  887.       /* relative xrefs must be resolved within the same section */
  888.       if (xdef->relsect->lnksec != ls) {
  889.         /* Illegal relative reference to symbol */
  890.         print_function_name(sec,xref->offset);
  891.         error(27,getobjname(sec->obj),sec->name,xref->offset-sec->offset,
  892.               xdef->name);
  893.         return;
  894.       }
  895.       x = (int32)xdef->value - (int32)xref->offset + xref->addend;
  896.       switch (xref->type) {
  897.         case R_REL32:
  898.           write32(be,p,(uint32)x);
  899.           break;
  900.   
  901.         case R_REL26:
  902.           biterr = checkrange(x,3,TRUE);
  903.           write32(be,p,(read32(be,p) & 0xfc000003)
  904.                        | (((uint32)x)&0x3fffffc));
  905.           break;
  906.   
  907.         case R_REL16:
  908.           biterr = checkrange(x,2,TRUE);
  909.           write16(be,p,(uint16)x);
  910.           break;
  911.  
  912.         /* @@@ currently no differentiation between the following */
  913.         case R_REL14:
  914.         case R_REL14_BRTAKEN:
  915.         case R_REL14_BRNTAKEN:
  916.           biterr = checkrange(x,2,TRUE);
  917.           write16(be,p,(read16(be,p) & 3) | (((uint16)x)&0xfffc));
  918.           break;
  919.   
  920.         case R_REL8:
  921.           biterr = checkrange(x,1,TRUE);
  922.           *p = (uint8)x;
  923.           break;
  924.   
  925.         default:  /* xref relocation type not supported */
  926.           ierror("%s%s%d",ierr_func,ierr_rtype,(int)xref->type);
  927.           break;
  928.       }
  929.       if (biterr) {  /* Relative reference to reloc symbol out of range! */
  930.         print_function_name(sec,xref->offset);
  931.         error(28,getobjname(sec->obj),sec->name,xref->offset-sec->offset,
  932.               xdef->name,xdef->value,(uint32)xref->addend,biterr);
  933.       }
  934.     }
  935.  
  936.     /*************************************************/
  937.     /* Base relative reference to relocatable symbol */
  938.     /*************************************************/
  939.     else if ((xref->type&R_MASK)==R_BASEREL) {
  940.       if (!gv->dest_object) {  /* destination is executable file? */
  941.         int32 d = ((int32)xdef->value + xref->addend) -
  942.                   fff[gv->dest_format]->baseoff;
  943.  
  944.         switch (xref->type) {
  945.           case R_BASEREL32:
  946.             write32(be,p,(uint32)d);
  947.             break;
  948.   
  949.           case R_BASEREL26:
  950.             biterr = checkrange(d,3,TRUE);
  951.             write32(be,p,(read32(be,p) & 0xfc000003)
  952.                          | (((uint32)d)&0x3fffffc));
  953.             break;
  954.   
  955.           case R_BASEREL16:
  956.             biterr = checkrange(d,2,TRUE);
  957.             write16(be,p,(uint16)d);
  958.             break;
  959.     
  960.           case R_BASEREL8:
  961.             biterr = checkrange(d,1,TRUE);
  962.             *p = (uint8)d;
  963.             break;
  964.  
  965.           default:  /* xref relocation type not supported */
  966.             ierror("%s%s%d",ierr_func,ierr_rtype,(int)xref->type);
  967.             break;
  968.         }
  969.       }
  970.  
  971.       else {  
  972.         /* destination is a relocatable object file, */
  973.         /* so create a new base-relative relocation entry */
  974.         int32 d = (int32)xdef->value + xref->addend;
  975.  
  976.         switch (xref->type) {
  977.           case R_BASEREL32:
  978.             write32(be,p,(uint32)d);
  979.             break;
  980.  
  981.           case R_BASEREL26:
  982.             biterr = checkrange(d,3,TRUE);
  983.             write32(be,p,(read32(be,p) & 0xfc000003)
  984.                          | (((uint32)d) & 0x3fffffc));
  985.             break;
  986.  
  987.           case R_BASEREL16:
  988.             biterr = checkrange(d,2,TRUE);
  989.             write16(be,p,(uint16)d);
  990.             break;
  991.   
  992.           case R_BASEREL8:
  993.             biterr = checkrange(d,1,TRUE);
  994.             *p = (uint8)d;
  995.             break;
  996.  
  997.           default:  /* xref relocation type not supported */
  998.             ierror("%s%s%d",ierr_func,ierr_rtype,(int)xref->type);
  999.             break;
  1000.         }
  1001.         newreloc(ls,xdef->relsect->lnksec,xref->offset,d,xref->type);
  1002.       }
  1003.  
  1004.       if (biterr) {  /* Base relative ref. to reloc symbol out of range! */
  1005.         print_function_name(sec,xref->offset);
  1006.         error(36,getobjname(sec->obj),sec->name,xref->offset-sec->offset,
  1007.               xdef->name,xdef->value,(uint32)xref->addend,biterr);
  1008.       }
  1009.     }
  1010.  
  1011.     /********************************************/
  1012.     /* Absolute reference to relocatable symbol */
  1013.     /********************************************/
  1014.     else {
  1015.       /* generates a new relocation entry */
  1016.       int32 x = (int32)xdef->value + xref->addend;
  1017.  
  1018.       switch (xref->type) {
  1019.         case R_ADDR16_LO:
  1020.           write16(be,p,(uint16)((uint32)x&0xffff));
  1021.           break;
  1022.  
  1023.         case R_ADDR16_HI:
  1024.           write16(be,p,(uint16)(((uint32)x>>16)&0xffff));
  1025.           break;
  1026.  
  1027.         case R_ADDR16_HA:
  1028.           write16(be,p,(uint16)((((uint32)x+0x8000)>>16)&0xffff));
  1029.           break;
  1030.  
  1031.         default:
  1032.           write32(be,p,(uint32)x);
  1033.           break;
  1034.       }
  1035.       newreloc(ls,xdef->relsect->lnksec,xref->offset,x,xref->type);
  1036.     }
  1037.   }
  1038.  
  1039.   else
  1040.     ierror("%sIllegal xdef-symbol type: %d",ierr_func,(int)xdef->type);
  1041. }
  1042.  
  1043.  
  1044. static void newreloc(struct LinkedSection *current_ls,
  1045.                      struct LinkedSection *base_ls,
  1046.                      unsigned long offs,int32 addend,uint8 type)
  1047. /* Create a new relocation node and insert it into the relocation */
  1048. /* list of the current LinkedSection. */
  1049. {
  1050.   struct Reloc *r = alloc(sizeof(struct Reloc));
  1051.  
  1052.   r->relocsect.lnk = base_ls;
  1053.   r->offset = offs;
  1054.   r->addend = addend;
  1055.   r->type = type;
  1056.   addtail(¤t_ls->relocs,&r->n);
  1057. }
  1058.  
  1059.  
  1060. static void assign_common(struct GlobalVars *gv)
  1061. /* Assign common symbols to a BSS section */
  1062. {
  1063.   struct ObjectUnit *obj = (struct ObjectUnit *)gv->selobjects.first;
  1064.   struct ObjectUnit *nextobj;
  1065.   struct Symbol *sym;
  1066.   int i;
  1067.  
  1068.   while (nextobj = (struct ObjectUnit *)obj->n.next) {
  1069.     if (obj->lnkfile->type != ID_SHAREDOBJ) {
  1070.       for (i=0; i<OBJSYMHTABSIZE; i++) {
  1071.         sym = obj->objsyms[i];
  1072.         while (sym) {
  1073.  
  1074.           if (sym->type == SYM_COMMON) {
  1075.             if (!(sym->relsect = find_sect_type(obj,ST_UDATA,
  1076.                                                 SP_READ|SP_WRITE))) {
  1077.               /* No bss section? Then create a new one. */
  1078.               /* @@@ maybe it would be better to use the object's */
  1079.               /*  file format rather than the dest. file format?  */
  1080.               sym->relsect = fff[gv->dest_format]->bssdefault(obj);
  1081.             }
  1082.           }
  1083.  
  1084.           sym = sym->obj_chain;
  1085.         }
  1086.       }
  1087.     }
  1088.     obj = nextobj;
  1089.   }
  1090. }
  1091.  
  1092.  
  1093. char *getobjname(struct ObjectUnit *obj)
  1094. /* if library: return "file name(object name)" */
  1095. /* else: return "file name" */
  1096. {
  1097.   char *fn = obj->lnkfile->filename;
  1098.  
  1099.   if (obj->lnkfile->type == ID_LIBARCH) {
  1100.     char *on = obj->objname;
  1101.     if (strlen(fn)+strlen(on)+2 < FNAMEBUFSIZE) {
  1102.       sprintf(namebuf,"%s(%s)",fn,on);
  1103.       return (namebuf);
  1104.     }
  1105.   }
  1106.   return (fn);
  1107. }
  1108.  
  1109.  
  1110. void print_function_name(struct Section *sec,unsigned long offs)
  1111. /* Try to determine the function to which the section offset */
  1112. /* belongs, by comparing with SYMI_FUNC-type symbol definitions. */
  1113. /* If this was successful and the current function is different */
  1114. /* from the last one printed, make an output to stderr. */
  1115. {
  1116.   static const char *infoname[] = { "", "object ", "function " };
  1117.   static struct Symbol *last_func=NULL;
  1118.   struct Symbol *sym,*func=NULL;
  1119.   int i;
  1120.  
  1121.   for (i=0; i<OBJSYMHTABSIZE; i++) {
  1122.     sym = sec->obj->objsyms[i];  /* scan all hash chains */
  1123.     while (sym) {
  1124.       if (sym->relsect == sec) {
  1125.         if (sym->info <= SYMI_FUNC) {
  1126.           if (sym->type == SYM_RELOC) {
  1127.             if ((unsigned long)sym->value <= offs) {
  1128.               if (sym->size) {  /* size of function specified? */
  1129.                 if ((unsigned long)(sym->value+sym->size) > offs) {
  1130.                   func = sym;
  1131.                   i = OBJSYMHTABSIZE;
  1132.                   break;  /* function found! */
  1133.                 }
  1134.               }
  1135.               else {  /* no size - find nearest... */
  1136.                 if (func) {
  1137.                   if (sym->value > func->value)
  1138.                     func = sym;
  1139.                 }
  1140.                 else
  1141.                   func = sym;
  1142.               }
  1143.             }
  1144.           }
  1145.         }
  1146.       }
  1147.       sym = sym->obj_chain;
  1148.     }
  1149.   }
  1150.  
  1151.   /* print function name */
  1152.   if (func && func!=last_func) {
  1153.     last_func = func;
  1154.     fprintf(stderr,"%s: In %s\"%s\":\n",getobjname(sec->obj),
  1155.             infoname[func->info],func->name);
  1156.   }
  1157. }
  1158.  
  1159.  
  1160. static char *maplibrary(struct GlobalVars *gv,struct InputFile *ifn)
  1161. /* Map a complete file into memory and return its address. */
  1162. /* The file's length is returned in *(p-sizeof(size_t)). */
  1163. /* All defined library paths will be searched for the file, */
  1164. /* before aborting. On success, the complete path of the loaded */
  1165. /* file is stored in namebuf[]. */
  1166. {
  1167.   char *p;
  1168.   char libname[FNAMEBUFSIZE];
  1169.  
  1170.   if (strlen(ifn->name) < (FNAMEBUFSIZE-16)) {
  1171.     if (ifn->dynamic) {
  1172.       sprintf(libname,"lib%s.so",ifn->name);
  1173.       if (p = searchlib(gv,libname,ifn->so_ver))
  1174.         return (p);
  1175.     }
  1176.     sprintf(libname,"lib%s.a",ifn->name);
  1177.     if (p = searchlib(gv,libname,-1))
  1178.       return (p);
  1179.     sprintf(libname,"%s.lib",ifn->name);
  1180.     if (p = searchlib(gv,libname,-1))
  1181.       return (p);
  1182.   }
  1183.   return (NULL);
  1184. }
  1185.  
  1186.  
  1187. static char *searchlib(struct GlobalVars *gv,char *libname,int so_ver)
  1188. {
  1189.   struct LibPath *lpn = (struct LibPath *)gv->libpaths.first;
  1190.   struct LibPath *nextlpn;
  1191.   char *p;
  1192.  
  1193.   if (p = scan_directory(".",libname,so_ver))
  1194.     return (p);
  1195.   while (nextlpn = (struct LibPath *)lpn->n.next) {
  1196.     if (p = scan_directory(lpn->path,libname,so_ver))
  1197.       return (p);
  1198.     lpn = nextlpn;
  1199.   }
  1200.   return (NULL);
  1201. }
  1202.  
  1203.  
  1204. static char *scan_directory(char *dirname,char *libname,int so_ver)
  1205. {
  1206.   size_t lnlen=strlen(libname);
  1207.   char *dd,*fname=NULL;
  1208.  
  1209.   if (so_ver < 0) {
  1210.     /* no need to scan the directory */
  1211.     fname = libname;
  1212.   }
  1213.   else {
  1214.     if (dd = open_dir(dirname)) {
  1215.       while (fname = read_dir(dd)) {
  1216.         if (!strncmp(fname,libname,lnlen)) {
  1217.           /* found a library archive/shared object name! */
  1218.           if (so_ver > 0) {  /* check version of shared object */
  1219.             if (fname[lnlen]=='.' && fname[lnlen+1]!=0) {
  1220.               if (atoi(&fname[lnlen+1]) >= so_ver)
  1221.                 break;
  1222.             }
  1223.           }
  1224.           else {
  1225.             /* otherwise the version is ignored - @@@ take highest ver. ? */
  1226.             break;
  1227.           }
  1228.         }
  1229.         else
  1230.           fname = NULL;
  1231.       }
  1232.       close_dir(dd);
  1233.     }
  1234.   }
  1235.  
  1236.   if (fname) {
  1237.     char *p;
  1238.     size_t dnlen;
  1239.  
  1240.     if ((dnlen = strlen(dirname)) < (FNAMEBUFSIZE-strlen(fname)-2)) {
  1241.       strcpy(namebuf,dirname);
  1242.       if (namebuf[dnlen-1]!='/' && namebuf[dnlen-1]!=':') {
  1243.         namebuf[dnlen++] = '/';
  1244.         namebuf[dnlen] = 0;
  1245.       }
  1246.       strncat(namebuf,fname,FNAMEBUFSIZE-dnlen-1);
  1247.       if (p = mapfile(namebuf))
  1248.         return (p);
  1249.     }
  1250.   }
  1251.   return (NULL);
  1252. }
  1253.  
  1254.  
  1255. static void addrelref(struct RelRef **rrptr,struct Section *sec)
  1256. /* if not already exists, add a new relative reference to another sect. */
  1257. {
  1258.   struct RelRef *rr;
  1259.  
  1260.   if (rr = *rrptr) {
  1261.     while (rr->next) {
  1262.       if (rr->refsec == sec)
  1263.         return;  /* reference already exists */
  1264.       rr = rr->next;
  1265.     }
  1266.   }
  1267.   else
  1268.     rr = (struct RelRef *)rrptr;
  1269.  
  1270.   rr->next = alloczero(sizeof(struct RelRef));
  1271.   rr->next->refsec = sec;
  1272. }
  1273.  
  1274.  
  1275. static void copyrelrefs(struct RelRef **rrptr,struct Section *sec)
  1276. /* transfer all rel. references from a single section to a linked-section */
  1277. {
  1278.   struct RelRef *old,*srr = sec->relrefs;
  1279.  
  1280.   while (old = srr) {
  1281.     addrelref(rrptr,srr->refsec);
  1282.     srr = srr->next;
  1283. #ifndef FASTALLOC
  1284.     free(old);
  1285. #endif
  1286.   }
  1287.   sec->relrefs = NULL;
  1288. }
  1289.  
  1290.  
  1291. static bool checkrelrefs(struct RelRef *rr,struct Section *sec)
  1292. /* Check, if there is a relative reference to the specified section. */
  1293. {
  1294.   while (rr) {
  1295.     if (rr->refsec == sec)
  1296.       return (TRUE);
  1297.     rr = rr->next;
  1298.   }
  1299.   return (FALSE);
  1300. }
  1301.  
  1302.  
  1303. bool trace_sym_access(struct GlobalVars *gv,char *name)
  1304. /* check if the symbol with this name should be traced */
  1305. {
  1306.   struct SymNames *sn;
  1307.  
  1308.   if (gv->trace_syms) {
  1309.     sn = gv->trace_syms[elf_hash(name)%TRSYMHTABSIZE];
  1310.     while (sn) {
  1311.       if (!strcmp(name,sn->name))
  1312.         return (TRUE);  /* symbol found! */
  1313.       sn = sn->next;
  1314.     }
  1315.   }
  1316.   return (FALSE);
  1317. }
  1318.  
  1319.  
  1320. static struct LinkedSection *create_lnksect(struct GlobalVars *gv,char *name,
  1321.                                             uint8 type,uint8 flags,
  1322.                                             uint8 protection,uint8 alignment)
  1323. /* create and initialize a LinkedSection node and include */
  1324. /* it in the global list */
  1325. {
  1326.   struct LinkedSection *ls = alloc(sizeof(struct LinkedSection));
  1327.  
  1328.   ls->index = gv->nsecs++;
  1329.   ls->name = name;
  1330.   ls->type = type;
  1331.   ls->flags = flags;
  1332.   ls->protection = protection;
  1333.   ls->alignment = alignment;
  1334.   ls->base = fff[gv->dest_format]->secbase(gv,ls);
  1335.   ls->size = ls->filesize = 0;
  1336.   initlist(&ls->sections);
  1337.   ls->relrefs = NULL;
  1338.   ls->data = NULL;
  1339.   initlist(&ls->relocs);
  1340.   initlist(&ls->xrefs);
  1341.   initlist(&ls->symbols);
  1342.   addtail(&gv->lnksec,&ls->n);
  1343.   return (ls);
  1344. }
  1345.  
  1346.  
  1347. static struct LinkedSection *find_lnksect(struct GlobalVars *gv,
  1348.                                           struct Section *sec)
  1349. /* find a LinkedSection node which fits the specified section */
  1350. {
  1351.   struct LinkedSection *lsn = (struct LinkedSection *)gv->lnksec.first;
  1352.   struct LinkedSection *nextlsn;
  1353.   uint8 f;
  1354.   int tl;
  1355.  
  1356.   while (nextlsn = (struct LinkedSection *)lsn->n.next) {
  1357.     if ((f = fff[gv->dest_format]->cmpsecflags(lsn->flags,sec->flags))
  1358.         != 0xff) {
  1359.       f &= ~SF_PORTABLE_MASK;
  1360.  
  1361.       /* target-specific linking */
  1362.       if ((tl = fff[gv->dest_format]->targetlink(gv,lsn,sec)) > 0) {
  1363.         /* target requires combining of sections */
  1364.         combine_sections(lsn,sec,f);
  1365.         return (lsn);
  1366.       }
  1367.  
  1368.       if (tl == 0) {  /* target wants to use the default rules */
  1369.  
  1370.         if (!gv->dest_object) {
  1371.           /* only, if an executable file will be created: */
  1372.  
  1373.           if (gv->small_code && lsn->type==sec->type==ST_CODE) {
  1374.             /* merge all code sections */
  1375.             combine_sections(lsn,sec,f);
  1376.             return (lsn);
  1377.           }
  1378.  
  1379.           if (gv->small_data) {
  1380.             if ((lsn->type==ST_DATA || lsn->type==ST_UDATA) &&
  1381.                 (sec->type==ST_DATA || sec->type==ST_UDATA)) {
  1382.               /* merge all data and bss sections */
  1383.               combine_sections(lsn,sec,f);
  1384.               return (lsn);
  1385.             }
  1386.           }
  1387.  
  1388.           if (checkrelrefs(lsn->relrefs,sec)) {
  1389.             /* we must link them together, because there are rel. refs */
  1390.             if ((lsn->type==ST_CODE || sec->type==ST_CODE) &&
  1391.                 lsn->type != sec->type)
  1392.               /* induces a maybe unwanted combination of code and data */
  1393.               error(58,sec_names[lsn->type],lsn->name,sec_names[sec->type],
  1394.                     sec->name,getobjname(sec->obj));
  1395.             combine_sections(lsn,sec,f);
  1396.             return (lsn);
  1397.           }
  1398.  
  1399.           if (!gv->multibase && (lsn->flags & sec->flags & SF_SMALLDATA)) {
  1400.             combine_sections(lsn,sec,f);
  1401.             return (lsn);
  1402.           }
  1403.         }
  1404.  
  1405.         /* standard check, if sections could be coalesced */
  1406.         if (!strcmp(sec->name,lsn->name) || /* same name or no name */
  1407.             *(sec->name)==0) {
  1408.           if (lsn->type == sec->type) {     /* same type */
  1409.             combine_sections(lsn,sec,f);
  1410.             return (lsn);
  1411.           }
  1412.         }
  1413.  
  1414.       } /* default rules */
  1415.     }
  1416.     lsn = nextlsn;
  1417.   }
  1418.   return (NULL);
  1419. }
  1420.  
  1421.  
  1422. static void combine_sections(struct LinkedSection *lsn,struct Section *sec,
  1423.                              uint8 target_flags)
  1424. {
  1425.   if (lsn->type == ST_UNDEFINED) {
  1426.     lsn->type = sec->type;
  1427.     lsn->flags = sec->flags;
  1428.   }
  1429.   else {
  1430.     lsn->flags &= SF_PORTABLE_MASK;
  1431.     lsn->flags |= (sec->flags&SF_SMALLDATA) | target_flags;
  1432.   }
  1433.  
  1434.   if (lsn->protection != sec->protection) {
  1435.     if (lsn->protection &&
  1436.         (lsn->protection & sec->protection) != sec->protection) {
  1437.       /* combine protection-flags of the two sections */
  1438.       char prot1[5],prot2[5];
  1439.       strncpy(prot1,protstring(lsn->protection),5);
  1440.       strncpy(prot2,protstring(lsn->protection|sec->protection),5);
  1441.       error(22,lsn->name,prot1,prot2);
  1442.     }
  1443.     lsn->protection |= sec->protection;
  1444.   }
  1445.  
  1446.   if (sec->alignment > lsn->alignment) {
  1447.     /* increase alignment to fit the needs of the new section */
  1448.     if (lsn->alignment)
  1449.       error(23,lsn->name,lsn->alignment,sec->alignment);
  1450.     lsn->alignment = sec->alignment;
  1451.   }
  1452. }
  1453.  
  1454.  
  1455. static void print_symbol(FILE *f,struct Symbol *sym)
  1456. /* print symbol name, type, value, etc. */
  1457. {
  1458.   fprintf(f,"  %s: %s%s%s, value 0x%x, size %d\n",sym->name,
  1459.           sym_bind[sym->bind],sym_type[sym->type],sym_info[sym->info],
  1460.           (int)sym->value,(int)sym->size);
  1461. }
  1462.  
  1463.  
  1464. static char *protstring(uint8 prot)
  1465. /* return pointer to protection string - example: "r---" or "rwxs" */
  1466. {
  1467.   static char *ps="----";
  1468.   char *p = ps;
  1469.  
  1470.   *p++ = (prot & SP_READ) ? 'r' : '-';
  1471.   *p++ = (prot & SP_WRITE) ? 'w' : '-';
  1472.   *p++ = (prot & SP_EXEC) ? 'x' : '-';
  1473.   *p++ = (prot & SP_SHARE) ? 's' : '-';
  1474.   return (ps);
  1475. }
  1476.